package com.cn.serverline.lineicp.productionLine.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cn.serverline.lineicp.productionLine.entity.ModelNodeLibrary;
import com.cn.serverline.lineicp.productionLine.enums.ModelNodeCodeEnum;
import com.cn.serverline.lineicp.productionLine.enums.ModelNodeLibraryEnum;
import com.cn.serverline.lineicp.productionLine.enums.ModelNodeLibraryException;
import com.cn.serverline.lineicp.productionLine.mapper.ModelNodeLibraryMapper;
import com.cn.serverline.lineicp.productionLine.param.ModelNode;
import com.cn.serverline.lineicp.productionLine.param.ModelNodeLibraryAddParam;
import com.cn.serverline.lineicp.productionLine.param.ModelNodeLibraryEditParam;
import com.cn.serverline.lineicp.productionLine.param.ModelNodeLibraryIdParam;
import com.cn.serverline.lineicp.productionLine.service.IModelNodeLibraryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.stylefeng.roses.kernel.db.api.factory.PageFactory;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * <p>
 * 型号节点库表 服务实现类
 * </p>
 *
 * @author Gmr
 * @since 2024-07-29
 */
@Service("ModelNodeLibraryServiceImpl")
public class ModelNodeLibraryServiceImpl extends ServiceImpl<ModelNodeLibraryMapper, ModelNodeLibrary> implements IModelNodeLibraryService {

    /**
     * 批量添加
     * @param modelNodeLibraryAddParamList 请求参数
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addBatch(List<ModelNodeLibraryAddParam> modelNodeLibraryAddParamList) {

        // 检验参数是否为空
        if(CollectionUtil.isEmpty(modelNodeLibraryAddParamList)){
            throw new ServiceException(ModelNodeLibraryException.MODEL_NODE_LIBRARY_ADD_NULL);
        }

        List<ModelNodeLibrary> modelNodeLibraryList = Lists.newArrayList();

        for (ModelNodeLibraryAddParam modelNodeLibraryAddParam : modelNodeLibraryAddParamList) {

            // 校验预案名称是否重复
            if(this.count(Wrappers.<ModelNodeLibrary>lambdaQuery()
                    .eq(ModelNodeLibrary::getModelCode, modelNodeLibraryAddParam.getModelCode())
                    .eq(ModelNodeLibrary::getPlanName, modelNodeLibraryAddParam.getPlanName())) > 0) {
                throw new ServiceException(ModelNodeLibraryException.PLAN_NAME_DUPLICATE);
            }

            List<ModelNode> modelNodeList = modelNodeLibraryAddParam.getModelNodeList();

            // 校验型号节点编码是否重复
            checkModelNodeCodeDuplicated(modelNodeList);

            boolean isDefault = this.count(Wrappers.<ModelNodeLibrary>lambdaQuery()
                    .eq(ModelNodeLibrary::getModelCode, modelNodeLibraryAddParam.getModelCode())) == 0;

            // 构建节点库数据
            modelNodeList.stream()
                    .map(modelNode -> {
                        ModelNodeLibrary modelNodeLibrary = BeanUtil.copyProperties(modelNode, ModelNodeLibrary.class);
                        modelNodeLibrary.setModelCode(modelNodeLibraryAddParam.getModelCode());
                        modelNodeLibrary.setPlanName(modelNodeLibraryAddParam.getPlanName());
                        modelNodeLibrary.setIsDefault(isDefault ? ModelNodeLibraryEnum.DEFAULT.getCode() :
                                ModelNodeLibraryEnum.NOT_DEFAULT.getCode());
                        return modelNodeLibrary;
                    })
                    .forEach(modelNodeLibraryList::add);
        }

        this.saveBatch(modelNodeLibraryList);
    }

    /**
     * 删除
     * @param id 请求参数
     */
    @Override
    public void del(ModelNodeLibraryIdParam id) {
        ModelNodeLibrary modelNodeLibrary = getModelNodeLibrary(id.getId());

        if(ModelNodeLibraryEnum.DEFAULT.getCode().equals(modelNodeLibrary.getIsDefault())) {
            throw new ServiceException(ModelNodeLibraryException.DEFAULT_DEL);
        }

        this.remove(Wrappers.<ModelNodeLibrary>lambdaQuery()
                .eq(ModelNodeLibrary::getModelCode, modelNodeLibrary.getModelCode())
                .eq(ModelNodeLibrary::getPlanName, modelNodeLibrary.getPlanName()));
    }

    /**
     * 编辑
     * @param modelNodeEditParam 请求参数
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(ModelNodeLibraryEditParam modelNodeEditParam) {

        List<ModelNodeLibrary> modelNodeLibraryList = Lists.newArrayList();

        // 获取节点库
        ModelNodeLibrary modelNodeLibrary = getModelNodeLibrary(modelNodeEditParam.getId());

        // 获取当前节点库所有节点
        Map<String, Long> modelNodeCodeofIdMap =  this.list(Wrappers.<ModelNodeLibrary>lambdaQuery()
                .eq(ModelNodeLibrary::getModelCode, modelNodeLibrary.getModelCode())
                .eq(ModelNodeLibrary::getPlanName, modelNodeLibrary.getPlanName()))
                .stream().collect(Collectors.toMap(ModelNodeLibrary::getModelNodeCode, ModelNodeLibrary::getId));
        List<ModelNode> modelNodeList = modelNodeEditParam.getModelNodeList();

        // 校验预案名称是否重复
        if(this.count(Wrappers.<ModelNodeLibrary>lambdaQuery()
                .eq(ModelNodeLibrary::getModelCode, modelNodeEditParam.getModelCode())
                .eq(ModelNodeLibrary::getPlanName, modelNodeEditParam.getPlanName())
                .notIn(ModelNodeLibrary::getId, modelNodeCodeofIdMap.values())) > 0) {
            throw new ServiceException(ModelNodeLibraryException.PLAN_NAME_DUPLICATE);
        }

        // 检验型号节点编码是否重复和型号节点编码是否存在
        checkModelNodeCodeDuplicated(modelNodeList);

        // 构建节点库数据
        modelNodeList.stream()
                .map(modelNode -> {
                    ModelNodeLibrary library = BeanUtil.copyProperties(modelNode, ModelNodeLibrary.class);
                    library.setId(modelNodeCodeofIdMap.get(modelNode.getModelNodeCode()));
                    library.setPlanName(modelNodeEditParam.getPlanName());
                    return library;
                }).forEach(modelNodeLibraryList::add);

        this.updateBatchById(modelNodeLibraryList);
    }

    /**
     * 查询
     * @param modelNodeLibrary 请求参数
     * @return 查询结果
     */
    @Override
    public List<Map<String, Object>> select(ModelNodeLibrary modelNodeLibrary) {
        List<Map<String, Object>> result = Lists.newArrayList();

        // 构建查询条件
        LambdaQueryWrapper<ModelNodeLibrary> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ModelNodeLibrary::getModelCode, modelNodeLibrary.getModelCode());

        // 获取结果
        Page<ModelNodeLibrary> modelNodeLibraryPage = this.page(PageFactory.defaultPage(), wrapper);
        List<ModelNodeLibrary> records = modelNodeLibraryPage.getRecords();

        // 根据预案名称分组
        Map<String, List<ModelNodeLibrary>> listMap = records.stream()
                .collect(Collectors.groupingBy(ModelNodeLibrary::getPlanName));

        listMap.forEach((planName, modelNodeLibraries) -> {
            Map<String, Object> map = Maps.newHashMap();

            Map<String, ModelNodeLibrary> modelNodeCodeMap = modelNodeLibraries.stream()
                    .collect(Collectors.toMap(ModelNodeLibrary::getModelNodeCode, Function.identity()));
            ModelNodeLibrary firstNode = modelNodeLibraries.get(0);
            map.put("id", firstNode.getId());
            map.put("planName", planName);
            map.put("modelCode", firstNode.getModelCode());
            map.put("isDefault", firstNode.getIsDefault());

            for (ModelNodeCodeEnum value : ModelNodeCodeEnum.values()) {
                map.put(value.getCode(), value.getDesc());
                map.put(value.getCode() + "Piece", modelNodeCodeMap.get(value.getCode()).getPiece());
                map.put(value.getCode() + "Day", modelNodeCodeMap.get(value.getCode()).getDay());
            }
            result.add(map);
        });

        return result;
    }

    /**
     * 设置默认
     * @param id 主键ID
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void markDefault(ModelNodeLibraryIdParam id) {
        ModelNodeLibrary modelNodeLibrary = getModelNodeLibrary(id.getId());

        this.update(Wrappers.<ModelNodeLibrary>lambdaUpdate()
                .set(ModelNodeLibrary::getIsDefault, ModelNodeLibraryEnum.NOT_DEFAULT.getCode())
                .eq(ModelNodeLibrary::getModelCode, modelNodeLibrary.getModelCode()));

        this.update(Wrappers.<ModelNodeLibrary>lambdaUpdate()
                .set(ModelNodeLibrary::getIsDefault, ModelNodeLibraryEnum.DEFAULT.getCode())
                .eq(ModelNodeLibrary::getPlanName, modelNodeLibrary.getPlanName())
                .eq(ModelNodeLibrary::getModelCode, modelNodeLibrary.getModelCode()));
    }

    /**
     * 获取节点库
     * @param id 主键ID
     * @return ModelNodeLibrary
     */
    private ModelNodeLibrary getModelNodeLibrary(String id) {
        if(StrUtil.isEmpty(id)) {
            throw new ServiceException(ModelNodeLibraryException.MODEL_NODE_LIBRARY_ID_NULL);
        }

        ModelNodeLibrary modelNodeLibrary = this.getById(id);

        if(ObjectUtil.isEmpty(modelNodeLibrary)){
            throw new ServiceException(ModelNodeLibraryException.MODEL_NODE_LIBRARY_NOT_EXIST);
        }
        return modelNodeLibrary;
    }

    /**
     * 校验型号节点编码是否重复
     *
     * @param modelNodeList 型号节点列表
     */
    private static void checkModelNodeCodeDuplicated(List<ModelNode> modelNodeList) {
        // 对型号节点编码去重,并校验是否存在型号节点编码
        List<String> noRepeat = modelNodeList.stream()
                .map(ModelNode::getModelNodeCode)
                .peek(ModelNodeCodeEnum::validate)
                .distinct().collect(Collectors.toList());

        if(noRepeat.size() < modelNodeList.size()){
            throw new ServiceException(ModelNodeLibraryException.MODEL_NODE_CODE_DUPLICATE);
        }
    }
}
